View Javadoc

1   // ClassLoader.java, created Thu Jul  4  4:50:03 2002 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.ClassLib.Common.java.lang;
5   
6   import java.util.HashMap;
7   import java.util.Map;
8   import java.io.ByteArrayInputStream;
9   import java.io.DataInputStream;
10  import java.security.ProtectionDomain;
11  import joeq.Class.PrimordialClassLoader;
12  import joeq.Class.jq_Array;
13  import joeq.Class.jq_Class;
14  import joeq.Class.jq_ClassFileConstants;
15  import joeq.Class.jq_CompiledCode;
16  import joeq.Class.jq_Reference;
17  import joeq.Class.jq_Type;
18  import joeq.Main.jq;
19  import joeq.Memory.StackAddress;
20  import joeq.Runtime.Reflection;
21  import joeq.Runtime.StackCodeWalker;
22  import joeq.UTF.Utf8;
23  import jwutil.util.Assert;
24  
25  /***
26   * ClassLoader
27   *
28   * @author  John Whaley <jwhaley@alum.mit.edu>
29   * @version $Id: ClassLoader.java 1941 2004-09-30 03:37:06Z joewhaley $
30   */
31  public abstract class ClassLoader {
32  
33      private boolean initialized;
34      private java.lang.ClassLoader parent;
35      private static ClassLoader scl;
36  
37      // additional instance field
38      private final Map/*<Utf8, jq_Type>*/ desc2type;
39  
40      // overridden instance method
41      void addClass(java.lang.Class c) {}
42  
43      // overridden constructors
44      protected ClassLoader(java.lang.ClassLoader parent) {
45          java.lang.SecurityManager security = java.lang.System.getSecurityManager();
46          if (security != null) {
47              security.checkCreateClassLoader();
48          }
49          Assert._assert(parent != null);
50          this.parent = parent;
51          Map m = new HashMap();
52          this.desc2type = m;
53          this.initialized = true;
54      }
55      protected ClassLoader() {
56          java.lang.SecurityManager security = java.lang.System.getSecurityManager();
57          if (security != null) {
58              security.checkCreateClassLoader();
59          }
60          java.lang.ClassLoader parent = getSystemClassLoader();
61          Assert._assert(parent != null);
62          this.parent = parent;
63          Map m = new HashMap();
64          this.desc2type = m;
65          this.initialized = true;
66      }
67  
68      native boolean isAncestor(ClassLoader cl);
69      static native RuntimePermission getGetClassLoaderPerm();
70      public native Class loadClass(java.lang.String name);
71  
72      // overridden methods.
73      public static java.lang.ClassLoader getSystemClassLoader() {
74          java.lang.Object o = PrimordialClassLoader.loader;
75          scl = (ClassLoader)o;
76          if (scl == null) {
77              return null;
78          }
79          java.lang.SecurityManager sm = java.lang.System.getSecurityManager();
80          if (sm != null) {
81              ClassLoader ccl = getCallerClassLoader();
82              if (ccl != null && ccl != scl) {
83                  try {
84                      if (!scl.isAncestor(ccl)) {
85                          sm.checkPermission(getGetClassLoaderPerm());
86                      }
87                  } catch (java.lang.Error x) {
88                      throw x;
89                  } catch (java.lang.Throwable x) {
90                      Assert.UNREACHABLE();
91                  }
92              }
93          }
94          o = scl;
95          return (java.lang.ClassLoader)o;
96      }
97  
98      // native method implementations.
99      public java.lang.Class defineClass0(java.lang.String name, byte[] b, int off, int len,
100                                          ProtectionDomain pd) {
101         // define a new class based on given name and class file structure
102         DataInputStream in = new DataInputStream(new ByteArrayInputStream(b, off, len));
103         // TODO: what should we do about protection domain???  ignore it???
104         if (name == null) throw new java.lang.ClassFormatError("name cannot be null when defining class");
105         if (name.startsWith("[")) throw new java.lang.ClassFormatError("cannot define array class with defineClass: "+name);
106         Utf8 desc = Utf8.get("L"+name.replace('.','/')+";");
107         if (this.getType(desc) != null)
108             throw new java.lang.ClassFormatError("class "+name+" already defined");
109         java.lang.Object o = this;
110         jq_Class c = jq_Class.newClass((java.lang.ClassLoader)o, desc);
111         Map desc2type = this.desc2type;
112         desc2type.put(desc, c);
113         c.load(in);
114         //in.close();
115         return Reflection.getJDKType(c);
116     }
117     private void resolveClass0(Class c) {
118         jq_Type t = c.jq_type;
119         t.load(); t.verify(); t.prepare();
120     }
121     private java.lang.Class findBootstrapClass(java.lang.String name) throws java.lang.ClassNotFoundException {
122         java.lang.Object o = PrimordialClassLoader.loader;
123         Assert._assert(this == o);
124         if (!name.startsWith("[")) name = "L"+name+";";
125         Utf8 desc = Utf8.get(name.replace('.','/'));
126         jq_Type k;
127         k = this.getOrCreateType(desc);
128         try {
129             k.load();
130         } catch (java.lang.ClassFormatError x) {
131             //this.unloadType(k); // ??? should we unload?
132             throw x;
133         } catch (java.lang.NoClassDefFoundError x) {
134             this.unloadType(k);
135             throw new java.lang.ClassNotFoundException(name);
136         }
137         return Reflection.getJDKType(k);
138     }
139     protected final java.lang.Class findLoadedClass(java.lang.String name) {
140         if (!name.startsWith("[")) name = "L"+name+";";
141         Utf8 desc = Utf8.get(name.replace('.','/'));
142         jq_Reference t = (jq_Reference) this.getType(desc);
143         if (t == null) return null;
144         // avoid recursive loading, because loading can use "Class.forName()"
145         if (t.getState() == jq_ClassFileConstants.STATE_UNLOADED)
146             t.load();
147         return Reflection.getJDKType(t);
148     }
149     static ClassLoader getCallerClassLoader() {
150         StackCodeWalker sw = new StackCodeWalker(null, StackAddress.getBasePointer());
151         sw.gotoNext(); sw.gotoNext(); sw.gotoNext();
152         jq_CompiledCode cc = sw.getCode();
153         if (cc == null) return null;
154         java.lang.Object o = cc.getMethod().getDeclaringClass().getClassLoader();
155         return (ClassLoader)o;
156     }
157 
158     // additional methods
159     public jq_Type getType(Utf8 desc) {
160         Assert._assert(jq.RunningNative);
161         Map desc2type = this.desc2type;
162         jq_Type t = (jq_Type)desc2type.get(desc);
163         return t;
164     }
165     public static jq_Type getOrCreateType(java.lang.ClassLoader loader, Utf8 desc) {
166         java.lang.Object o = loader;
167         return ((ClassLoader)o).getOrCreateType(desc);
168     }
169     public jq_Type getOrCreateType(Utf8 desc) {
170         if (!jq.RunningNative)
171             return PrimordialClassLoader.loader.getOrCreateBSType(desc);
172         Map desc2type = this.desc2type;
173         jq_Type t = (jq_Type)desc2type.get(desc);
174         if (t == null) {
175             if (desc.isDescriptor(jq_ClassFileConstants.TC_CLASS)) {
176                 java.lang.Object o = this;
177                 t = jq_Class.newClass((java.lang.ClassLoader)o, desc);
178             } else {
179                 if (!desc.isDescriptor(jq_ClassFileConstants.TC_ARRAY))
180                     Assert.UNREACHABLE("bad descriptor! "+desc);
181                 Utf8 elementDesc = desc.getArrayElementDescriptor();
182                 jq_Type elementType;
183                 elementType = this.getOrCreateType(elementDesc); // recursion
184                 java.lang.Object o = this;
185                 t = jq_Array.newArray(desc, (java.lang.ClassLoader)o, elementType);
186             }
187             desc2type.put(desc, t);
188         }
189         return t;
190     }
191     public void unloadType(jq_Type t) {
192         if (!jq.RunningNative) {
193             PrimordialClassLoader.loader.unloadBSType(t);
194             return;
195         }
196         Map desc2type = this.desc2type;
197         desc2type.remove(t.getDesc());
198     }
199 
200 }